import { and, eq, inArray, type SQL, sql } from "drizzle-orm";
import z from "zod";
import { db } from "../lib/db";
import { tests } from "../schemas/tests";
import {
  type Issue,
  issues as issueValues,
  type Label,
  type Status,
  statuses as statusValues,
} from "../types/allure";

export const QueryTestsSchema = z.object({
  reportId: z.string(),
  statuses: z.array(z.string()).optional().nullable(),
  owners: z.array(z.string()).optional().nullable(),
  issues: z.array(z.string()).optional().nullable(),
});

export type QueryTestsParams = z.infer<typeof QueryTestsSchema>;

export async function getTests(params: QueryTestsParams) {
  const { reportId, statuses, owners, issues } = params;

  const filters: SQL[] = [];

  if (statuses && statuses.length > 0) {
    const validStatuses = statuses.filter((status): status is Status =>
      statusValues.includes(status as Status),
    );
    filters.push(inArray(tests.status, validStatuses));
  }

  if (owners && owners.length > 0) {
    const validOwners = owners.filter(Boolean);
    if (validOwners.length > 0) {
      const conditions = validOwners.map(
        (owner) =>
          sql<
            Label[]
          >`${tests.labels} @> ${JSON.stringify({ name: "owner", value: owner })}::jsonb`,
      );
      const conditionSql = sql.join(conditions, sql.raw(" OR "));
      filters.push(conditionSql);
    }
  }

  if (issues && issues.length > 0) {
    const validIssues = issues.filter((issue): issue is Issue =>
      issueValues.includes(issue as Issue),
    );
    filters.push(inArray(tests.issue, validIssues as Issue[]));
  }
  return await db
    .select()
    .from(tests)
    .where(and(...filters, eq(tests.reportId, reportId)));
}

export const UpdateTestSchema = z.object({
  id: z.string(),
  issue: z.enum(issueValues),
  editer: z.string(),
});

export type UpdateTestParams = z.infer<typeof UpdateTestSchema>;

export async function updateTest(params: UpdateTestParams) {
  const { id, issue, editer } = params;

  const [result] = await db
    .update(tests)
    .set({ issue, editer })
    .where(eq(tests.id, id))
    .returning();

  return result;
}
